package at.jaki.ubb.crawling.demo.interpreter;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import at.jaki.ubb.crawling.api.DataInterpreter;
import at.jaki.ubb.crawling.demo.db.FsDataBase;
import at.jaki.ubb.crawling.demo.model.Point;
import at.jaki.ubb.crawling.demo.model.StarData;
import at.jaki.ubb.crawling.demo.ui.UiManager;

public class InterpreterMain implements DataInterpreter {

	private static final Logger LOG = Logger.getLogger(InterpreterMain.class);
	private static final double MAX_DIF = 5;
	private static final int PREVS = 3;

	public void notify(List<String> guids) {
		FsDataBase db = FsDataBase.getInstance();
		for (String guid : guids) {
			try {
				StarData sd = db.getStarDataByGUID(guid);
				StarData sdNorm = normalize(sd);
				FsDataBase.getInstance().save(sdNorm);
				UiManager.getInstance().addStar(FsDataBase.getDisplay(sdNorm));
			} catch (Exception e) {
				LOG.error("could not find star with guid " + guid);
			}
		}

	}

	private StarData normalize(StarData sd) {

		List<Point> list = sd.getList();

		// avarage luminosity
		double avY = 0;
		for (Point p : list) {
			avY += p.getY();
		}
		avY = avY / list.size();

		// avarage distance from avarage
		double avD = 0;
		for (Point p : list) {
			avD += Math.abs(avY - p.getY());
		}
		avD /= list.size();

		double normAvgY = 0;

		List<Point> listN = new ArrayList<Point>();
		for (Point p : list) {
			double d = Math.abs(p.getY() - avY);
			if (d <= MAX_DIF * avD) {
				listN.add(p);
				normAvgY += p.getY();
			}
		}
		normAvgY /= listN.size();

		int magicNumber = getMacigNumber(listN);

		StarData data = copyHeader(sd);
		data.setList(listN);
		data.setNormalized(true);
		data.setMagicNumber(magicNumber);
		data.setAvg(normAvgY);

		return data;
	}

	private int getMacigNumber(List<Point> listN) {

		double sum = 0;
		double max = 0;
		int count = 0;

		Double[] prevValues = new Double[PREVS];
		for (Point p : listN) {
			Double d = calc(p.getY(), prevValues);
			shl(prevValues);
			prevValues[PREVS - 1] = p.getY();
			if (d != null && d < 0) {
				sum += d;
				count++;
				max = Math.min(max, d);
			}
		}

		double avgDrop = sum / (double) count;

		double mn = max / avgDrop;

		return (int) mn;
	}

	private Double calc(double y, Double[] prevValues) {
		try {
			double r = 0;
			for (Double d : prevValues) {
				r += (y - d);
			}
			return r;
		} catch (NullPointerException e) {
			return null;
		}
	}

	private void shl(Double[] prevValues) {
		for (int i = 0; i < prevValues.length - 1; i++) {
			prevValues[i] = prevValues[i + 1];
		}
	}

	private static StarData copyHeader(StarData sd) {
		StarData sd2 = new StarData();
		sd2.setId(sd.getId());
		sd2.setRelease(sd.getRelease());
		sd2.setStartTime(sd.getStartTime());
		return sd2;
	}

}
